﻿#include "rec_frmidx.h"

CRecFrameIdx::CRecFrameIdx()
{
	m_frameBuf = NULL;
	m_frmBufSz = 0;

	m_gpsBuf   = NULL;
	m_gpsBufSz = 0;

	m_pFrmIdx = NULL;
	m_pGPSIdx = NULL;
	m_buf = NULL;
	m_secSize = 512;
	m_delayWtSecs = 15;	//15secs最大延时写入时间
	m_lastWritePos =0 ;
	m_bufSize     = 0;
	m_lastFrmTm   = 0;
	m_lastFrmOffset = STFS_REC_DATA_OFFSET;	;
	m_lastFrmLen  = 0;
}

CRecFrameIdx::~CRecFrameIdx()
{
	if(NULL != m_frameBuf)
	{
		delete [] m_frameBuf;
	}
	if(NULL != m_gpsBuf)
	{
		delete [] m_gpsBuf;
	}
	if(NULL != m_buf)
	{
		delete [] m_buf;
	}

	m_indexOffset = 0;
	m_diffOffset  = 0;
	m_bufSize     = 0;
	m_bOpen       = false;
	m_lastWritePos =0 ;
}
/*
//
// indexOffset:索引区的起始地址
// diskSecSize 主要是为返回对齐后的缓冲块,减少磁盘ＩＯ
*/
int  CRecFrameIdx::Open(uint32_t bufSize,uint32_t indexOffset,uint32_t diskSecSize)
{
	int ret = 0;
	if(NULL == m_buf)
	{
		m_buf = new uchar_t[bufSize];
	}
	else
	{
		if(m_bufSize == bufSize)
		{
			ret = ERR_BUF_OPENED;
			return ret;
		}
		else
		{
			delete [] m_buf;
			m_buf = new uchar_t[bufSize];
		}
	}

	memset(m_buf,0,bufSize);
	m_indexOffset = indexOffset;
	m_bufSize     = bufSize;
	m_secSize     = diskSecSize;
	m_bOpen       = true;

	m_diffOffset  = 0;
	m_frmIdxCnt   = 0;
	m_gpsIdxCnt   = 0;
	m_dataPos = m_lastWritePos =0 ;
	time(&m_lastWtTm);
	return ret;
}

void  CRecFrameIdx::InitStartPos(uint32_t dataPos,uint32_t idxPos)
{
	m_dataPos = m_lastWritePos =dataPos ;
	m_indexOffset = idxPos;
}

void CRecFrameIdx::Reset()
{
	memset(m_buf,0,m_bufSize);
	m_diffOffset  = 0;
	m_frmIdxCnt   = 0;
	m_gpsIdxCnt   = 0;
	m_dataPos     = m_lastWritePos =0 ;
	time(&m_lastWtTm);
}
//写入视频帧索引
int  CRecFrameIdx::WriteFrameIndex(const void * idxBuf,uint32_t idxSize)
{
	if(NULL == idxBuf)
	{
		return ERR_DATA_BUF_EMPYT;
	}
	if(m_dataPos + idxSize >= m_bufSize)
	{
		return ERR_OVER_BUFSIZE;
	}

	if(m_dataPos + idxSize > STFS_REC_DATA_OFFSET)
	{
		return ERR_DATA_AREA;
	}

	m_lock.Lock();

	if(m_lastWritePos > (m_bufSize/2))
	{
		MoveData();
	}
	memcpy(m_buf + m_dataPos,idxBuf,idxSize);
	m_dataPos += idxSize;
	m_frmIdxCnt++;

	m_lock.UnLock();

	return 0;
}

//写入GPS信息
int  CRecFrameIdx::WriteGpsInfo(const void * gpsBuf,uint32_t gpsInfoSize)
{
	if(NULL == gpsBuf)
	{
		return ERR_DATA_BUF_EMPYT;
	}
	if(!m_bOpen)
	{
		return ERR_FILE_NOOPEN;
	}
	if(m_dataPos + gpsInfoSize >= m_bufSize)
	{
		return ERR_OVER_BUFSIZE;
	}
	if(m_dataPos + gpsInfoSize > STFS_REC_DATA_OFFSET)
	{
		return ERR_DATA_AREA;
	}
	m_lock.Lock();
	if(m_lastWritePos > (m_bufSize/2))
	{
		MoveData();
	}

	memcpy(m_buf + m_dataPos,gpsBuf,gpsInfoSize);
	m_dataPos += gpsInfoSize;
	m_gpsIdxCnt++;

	m_lock.UnLock();
	return 0;
}

int  CRecFrameIdx::MoveData()
{
	uint32_t move_off = m_bufSize/2;
	if(m_lastWritePos > move_off)
	{
		return ERR_PARAM;
	}
	CROSS_ASSERT(m_dataPos >= m_lastWritePos);
	if(m_dataPos < move_off )
	{
		return ERR_DATA_AREA;
	}

	int move_size = m_dataPos - move_off;
	memcpy(m_buf,m_buf + move_off,move_size);
	m_dataPos -= move_off;
	m_lastWritePos -= move_off;

	return 0;
}
//检测索引是否需要及时写入

bool CRecFrameIdx::IsNeedFlush()
{
	time_t now;
	time(&now);
	int diff = (int)(now - m_lastWtTm);
	m_lock.Lock();
	uint32_t dataLen = m_dataPos - m_lastWritePos;
	m_lock.UnLock();
	//1.通过数据长度判断
	if(dataLen == 0 )
	{
		return false;
	}

	if(dataLen > m_secSize /3) //尽量让磁盘扇区写入的数据减少
	{
		m_lastWtTm = now;
		return true;
	}
	//2.通过时间条件判断
	if( diff > (int)m_delayWtSecs ||
		diff < 0 )
	{
		m_lastWtTm = now;
		return true;
	}

	return false;
}
//录像时使用
//获取要写入的偏移
uint32_t  CRecFrameIdx::GetWriteOffset()
{
	uint32_t writePos = m_indexOffset + m_dataPos + m_diffOffset;
	writePos = SIZE_ROUND_ALIGN(writePos,m_secSize);
	return writePos;
}

uchar_t *  CRecFrameIdx::GetWriteBuffAddr(uint32_t & writePos,uint32_t & wtSize)
{
	if( NULL == m_buf)
	{
		return NULL;
	}
	uint32_t bufStart   = SIZE_ROUND_ALIGN(m_lastWritePos,m_secSize);

	uint32_t dataOffset = SIZE_ROUND_UP(m_dataPos,m_secSize);

	writePos =  bufStart;
	wtSize   = dataOffset - bufStart;
	//补齐后面数据为0
	memset(m_buf + m_dataPos,0,dataOffset - m_dataPos);
	return (m_buf + bufStart);
}

/*
#define STFS_REC_IDX_SIG	      mmioFOURCC('R','I','D','X')//索引标识
#define STFS_GPS_IDX_SIG	      mmioFOURCC('G','P','S','I')//GPS INFO
#define STFS_REC_SEG_SIG		  mmioFOURCC('R','S','E','G')//录像段标识
*/

uint32_t  CRecFrameIdx::GetDataSize2KeyFrm(int lastIdxCnt,uint32_t lastOffset)
{
	uint32_t maxDataSize = 0;
	uint32_t tmpSize     = 0;
	int chkCnt = lastIdxCnt;
	uint32_t diff   = 0;

	STFS_REC_IDX * pIdx  = (STFS_REC_IDX *)(m_buf + m_dataPos - REC_INDEX_LEN);
	//从最近的5个I帧来估算I帧的平均数据大小，5，4，3，2.1
	while(diff <= m_dataPos)
	{
		if(diff != 0)
		{
			pIdx  = (STFS_REC_IDX *)(m_buf + m_dataPos - diff);
		}
		if(pIdx->magic == STFS_REC_IDX_SIG)
		{
			tmpSize = lastOffset - pIdx->offset;
			if(tmpSize > maxDataSize)
			{
				maxDataSize = tmpSize;
			}

			chkCnt--;
			diff += REC_INDEX_LEN;
			lastOffset = pIdx->offset;
			continue;
		}
		if(0 == chkCnt)
		{
			break;
		}
		diff++;
	}

	return maxDataSize;
}

int CRecFrameIdx::AnalyseData(uint32_t headDiff)
{

	uint32_t diff   = 0;
	uint32_t zeroCnt = 0;

	STFS_REC_IDX * pIdx  = NULL;

	while(diff <= SIZE_8KB)
	{
		pIdx  = (STFS_REC_IDX *)(m_buf + diff);
		if(pIdx->magic == STFS_REC_IDX_SIG)
		{
			break;
		}
		diff++;
	}
	m_dataPos = diff;
	//搬移数据
	uint32_t dataSize  = m_bufSize - diff;

	m_indexOffset = STFS_REC_IDX_OFFSET;

	m_gpsIdxCnt = 0;
	m_gpsIdxCnt = 0;
	while(diff <= dataSize)
	{
	    pIdx  = (STFS_REC_IDX *)(m_buf + diff);
		if(pIdx->magic == STFS_REC_IDX_SIG)
		{
			diff += REC_INDEX_LEN;
			m_frmIdxCnt++;
			zeroCnt = 0;
			m_lastFrmTm     = pIdx->tmMS;
			m_lastFrmOffset = pIdx->offset;		//文件中的位置
			m_lastFrmLen    = pIdx->frameLen;
			m_dataPos = diff;
			continue;
		}
		else if(pIdx->magic == STFS_GPS_IDX_SIG)
		{
			diff += GPS_INDEX_LEN;
			m_gpsIdxCnt++;
			zeroCnt = 0;
			m_dataPos = diff;
			continue;
		}
		else if(pIdx->magic == 0)
		{
			zeroCnt++;
			if(zeroCnt >= 40)
			{
				break;
			}
		}

		diff++;
	}

	TRACE("Detect data offset %d index cnt %d gps cnt %d \n",m_dataPos,m_frmIdxCnt,m_gpsIdxCnt);
	return 0;
}

int CRecFrameIdx::GetFrmIdxData(STFS_REC_IDX * idxBuf,int maxNum)
{
	int realNum = 0;
	uint32_t diff   = 0;

	//搬移数据
	uint32_t idxBufOff = STFS_REC_IDX_OFFSET ;
	uint32_t dataSize  = m_bufSize - idxBufOff;
	//搬移索引缓冲
	//memcpy(m_buf,m_buf + idxBufOff,dataSize);
	//memset(m_buf + dataSize,0,m_bufSize - dataSize);

	STFS_REC_IDX * pIdx  = NULL;
	memset(idxBuf,0, maxNum * REC_INDEX_LEN);

	while(diff <= SIZE_8KB)
	{
		pIdx  = (STFS_REC_IDX *)(m_buf + diff);
		if(pIdx->magic == STFS_REC_IDX_SIG)
		{
			break;
		}
		diff++;
	}

	uint32_t lastTime = 0;

	while(diff <= dataSize)
	{
		pIdx = (STFS_REC_IDX *)(m_buf + diff);
		if(pIdx->magic == STFS_REC_IDX_SIG)
		{
// 			if(pIdx->tmSec < lastTime)
// 			{
// 				break;
// 			}
			diff += REC_INDEX_LEN;
			memcpy(&idxBuf[realNum],pIdx,REC_INDEX_LEN);
			realNum++;
			continue;
		}
		else if(pIdx->magic == STFS_GPS_IDX_SIG)
		{
			diff += GPS_INDEX_LEN;
			continue;
		}
		else if(pIdx->magic == 0)
		{
			diff++;
			continue;
		}

		diff++;
	}


	return realNum;
}

int CRecFrameIdx::GetGpsIdxData(STFS_GPS_IDX * idxBuf,int maxNum)
{
	int realNum = 0;
	uint32_t diff   = 0;

	//搬移数据

	STFS_REC_IDX * pIdx  = NULL;

	while(diff <= SIZE_8KB)
	{
		pIdx  = (STFS_REC_IDX *)(m_buf + diff);
		if(pIdx->magic == STFS_REC_IDX_SIG)
		{
			break;
		}
		diff++;
	}

	uint32_t idxBufOff = STFS_REC_IDX_OFFSET ;
	uint32_t dataSize  = m_bufSize - idxBufOff;

	while(diff <= dataSize)
	{
		pIdx = (STFS_REC_IDX *)(m_buf + diff);
		if(pIdx->magic == STFS_REC_IDX_SIG)
		{
			diff += REC_INDEX_LEN;
			continue;
		}
		else if(pIdx->magic == STFS_GPS_IDX_SIG)
		{
			diff += GPS_INDEX_LEN;
			memcpy(&idxBuf[realNum],pIdx,GPS_INDEX_LEN);
			realNum++;
			continue;
		}
		else if(pIdx->magic == 0)
		{
			diff++;
			continue;
		}
		diff++;
	}

	return realNum;
}
